//
// Snake.cpp for nibbler in /home/lefebv_w//workspace/cpp/nibbler/googleCode
// 
// Made by damien lefebvre
// Login   <lefebv_w@epitech.net>
// 
// Started on  Fri Mar 15 21:10:28 2013 damien lefebvre
// Last update Sun Mar 24 21:58:59 2013 damien lefebvre
//

#include	"Snake.hh"

/* Class PartOfSnake */

Snake::PartOfSnake::PartOfSnake(unsigned int pos_x, unsigned int pos_y, IGraphicLibrary::e_TypeOfCase t, IGraphicLibrary::e_ListOfImage img, IGraphicLibrary::e_Direction direction)
  : m_pos_x(pos_x), m_pos_y(pos_y), m_type(t), m_direction(direction), m_img(img)
{}

void		Snake::PartOfSnake::move(unsigned int new_pos_x, unsigned int new_pos_y, IGraphicLibrary::e_Direction new_direction)
{
  m_direction = new_direction;
  m_pos_x = new_pos_x;
  m_pos_y = new_pos_y;
}

void		Snake::PartOfSnake::draw(IGraphicLibrary & graph) const
{
  graph.draw(m_pos_x, m_pos_y, m_img, m_direction);
}

void		Snake::PartOfSnake::setImage(IGraphicLibrary::e_ListOfImage img)
{
  m_img = img;
}

void		Snake::PartOfSnake::setDirection(IGraphicLibrary::e_Direction dir)
{
  m_direction = dir;
}

IGraphicLibrary::e_Direction	Snake::PartOfSnake::getDirection(void) const
{
  return (m_direction);
}

unsigned int	Snake::PartOfSnake::getPosX(void) const
{
  return (m_pos_x);
}

unsigned int	Snake::PartOfSnake::getPosY(void) const
{
  return (m_pos_y);
}

/* Class Snake */

Snake::Snake(unsigned int pos_x, unsigned int pos_y, unsigned int nbOfPart)
  : m_nbmove(0), m_pos_x(pos_x), m_pos_y(pos_y), m_lastmove(0), m_direction(IGraphicLibrary::UP), m_partToAdd(0), m_olddirection(IGraphicLibrary::UP)
{
  unsigned int i;

  m_body.push_back(new PartOfSnake(pos_x, pos_y, IGraphicLibrary::SNAKEHEAD, IGraphicLibrary::IMG_SNAKEHEAD, m_direction));
  for (i = 1; i < nbOfPart - 1; i++)
    {
      m_body.push_back(new PartOfSnake(pos_x, pos_y + i, IGraphicLibrary::SNAKE, (IGraphicLibrary::e_ListOfImage)(IGraphicLibrary::IMG_SNAKE_PART1 + (i % 2)), m_direction));
    }
      m_body.push_back(new PartOfSnake(pos_x, pos_y + i, IGraphicLibrary::SNAKE, IGraphicLibrary::IMG_SNAKEFOOT, m_direction));
}

void		Snake::newSnake(unsigned int pos_x, unsigned int pos_y, unsigned int nbOfPart)
{
  for (unsigned int i = 0; i < m_body.size(); i++)
    {
      delete m_body[i];
    }
  m_body.clear();
  m_pos_x = pos_x;
  m_pos_y = pos_y;
  m_lastmove = 0;
  m_direction = IGraphicLibrary::UP;
  m_partToAdd = 0;

  unsigned int i;
  m_body.push_back(new PartOfSnake(pos_x, pos_y, IGraphicLibrary::SNAKEHEAD, IGraphicLibrary::IMG_SNAKEHEAD, m_direction));
  for (i = 1; i < nbOfPart - 1; i++)
    {
      m_body.push_back(new PartOfSnake(pos_x, pos_y + i, IGraphicLibrary::SNAKE, (IGraphicLibrary::e_ListOfImage)(IGraphicLibrary::IMG_SNAKE_PART1 + (i % 2)), m_direction));
    }
      m_body.push_back(new PartOfSnake(pos_x, pos_y + i, IGraphicLibrary::SNAKE, IGraphicLibrary::IMG_SNAKEFOOT, m_direction));
}

Snake::~Snake(void)
{
  for (unsigned int i = 0; i < m_body.size(); i++)
    {
      delete m_body[i];
    }
}

void		Snake::setDirection(IGraphicLibrary::e_Direction t)
{
  if (t != m_olddirection && t != (IGraphicLibrary::e_Direction)((m_olddirection + 2) % 4) && t != m_direction && t != (IGraphicLibrary::e_Direction)((m_direction + 2) % 4))
    {
      m_olddirection = m_direction;
      m_direction = t;
    } 
}

bool		Snake::addPart(std::vector< std::vector<Case *> > const & map, unsigned int nbOfPart)
{
  unsigned int				new_pos_x;
  unsigned int				new_pos_y;
  PartOfSnake				*last_part;
  unsigned int				i;

  if (nbOfPart != 0)
    {
      m_partToAdd += nbOfPart;
      return (false);
    }
  last_part = m_body[m_body.size() - 1];
  i = 0;
  do
    {
      new_pos_x = last_part->getPosX();
      new_pos_y = last_part->getPosY();
      getNewPos(new_pos_x, new_pos_y, (IGraphicLibrary::e_Direction)((last_part->getDirection() + i) % 4));
      if (++i == 4)
	return (true);
    } while (new_pos_x >= map.size() || new_pos_y >= map[new_pos_x].size() ||
	     map[new_pos_x][new_pos_y]->getType() != IGraphicLibrary::EMPTY);
  m_body.push_back(new PartOfSnake(new_pos_x, new_pos_y, IGraphicLibrary::SNAKE, IGraphicLibrary::IMG_SNAKEFOOT, last_part->getDirection()));
  m_body[m_body.size() - 2]->setImage(IGraphicLibrary::IMG_SNAKE_PART1);
  return (false);
}

void		Snake::getNewPos(unsigned int & pos_x, unsigned int & pos_y, IGraphicLibrary::e_Direction d, bool is_part)
{
  int nb;

  if (is_part)
    nb = -1;
  else
    nb = 1;
  switch (d)
    {
    case IGraphicLibrary::UP :
      pos_y -= nb;
      break;
    case IGraphicLibrary::DOWN :
      pos_y += nb;
      break;
    case IGraphicLibrary::LEFT :
      pos_x -= nb;
      break;
    case IGraphicLibrary::RIGHT :
      pos_x += nb;
      break;
    }
}

void		Snake::move(t_frame frame, t_frame vitesse, std::vector< std::vector<Case *> > const & map)
{
  unsigned int	new_pos_x;
  unsigned int	new_pos_y;
  unsigned int	old_pos_x;
  unsigned int	old_pos_y;
  IGraphicLibrary::e_Direction	old_direction;
  IGraphicLibrary::e_Direction	new_direction;

  if (frame - m_lastmove < vitesse)
    return ;
  new_pos_x = m_pos_x;
  new_pos_y = m_pos_y;
  new_direction = m_direction;
  getNewPos(new_pos_x, new_pos_y, m_direction, false);
  for (unsigned int i = 0; i < m_body.size(); i++)
    {
      old_pos_x = m_body[i]->getPosX();
      old_pos_y = m_body[i]->getPosY();
      old_direction = m_body[i]->getDirection();
      m_body[i]->move(new_pos_x, new_pos_y, new_direction);
      new_pos_x = old_pos_x;
      new_pos_y = old_pos_y;
      new_direction = old_direction;
      if (i != m_body.size() - 1 && i != 0)
	{
	  if ((i + m_nbmove) % 2 == 0)
	    m_body[i]->setImage(IGraphicLibrary::IMG_SNAKE_PART1);
	  else
	    m_body[i]->setImage(IGraphicLibrary::IMG_SNAKE_PART2);
	}
    }
  m_nbmove = (m_nbmove + 1) % 2;
  m_pos_x = m_body[0]->getPosX();
  m_pos_y = m_body[0]->getPosY();
  m_body[m_body.size() - 1]->setDirection(m_body[m_body.size() - 2]->getDirection());
  m_lastmove = frame;
  m_olddirection = m_direction;
  if (m_partToAdd != 0)
    {
      addPart(map);
      m_partToAdd--;
    } 
}

bool		Snake::checkEndOfGame(std::vector< std::vector<Case *> > const & map) const
{
  for (unsigned int i = 1; i < m_body.size(); i++)
    {
      if (m_body[i]->getPosX() == m_pos_x &&
	  m_body[i]->getPosY() == m_pos_y)
	{
	  return (true);
	}
    }
  if (m_pos_x >= map.size() || m_pos_y >= map[m_pos_x].size() ||
      map[m_pos_x][m_pos_y]->getType() != IGraphicLibrary::EMPTY)
    {
      return (true);
    }
  return (false);
}

void		Snake::draw(IGraphicLibrary & graph) const
{
  for (unsigned int i = 0; i < m_body.size(); i++)
    {
      m_body[i]->draw(graph);
    }
}

bool		Snake::checkIntersection(unsigned int pos_x, unsigned int pos_y) const
{
  for (unsigned int i = 0; i < m_body.size(); i++)
    {
      if (m_body[i]->getPosX() == pos_x && m_body[i]->getPosY() == pos_y)
	return (true);
    }
  return (false);
}

unsigned int	Snake::getPosX(void) const
{
  return (m_pos_x);
}

unsigned int	Snake::getPosY(void) const
{
  return (m_pos_y);
}

t_frame		Snake::getLastMove(void) const
{
  return (m_lastmove);
}
